<!--
    by: yuanbiao 2021年06月09日
    name: x-file-viewer
    notes:
-->
<template>
  <div ref="xFileViewer" :class="[`${prefixCls}`, `${prefixCls}-${size}`]">
    <component v-if="fileActiveComponent" :is="fileActiveComponent" :options="componentOptions" :size="size"></component>
    <div v-else :class="[`${prefixCls}__empty`, 'text-center']">
      <p><i class="xvu-iconfont xvu-book"></i></p>
      <p>文件查看器</p>
    </div>
    <div v-show="showMenu"
      :class="[`${prefixCls}__menu`, statusCtrl.collapsePlaylist ? `${prefixCls}__menu-collapse` : '']"
    >
      <div :class="`${prefixCls}__menu_head`">
        <div class="fl"><i class="xvu-iconfont xvu-list"></i>文件列表</div>
        <div class="fr" v-show="statusCtrl.showMenuDelete" @click="menuDeleteClick">
          <i class="xvu-iconfont xvu-delete" title="清空列表"></i>
        </div>
      </div>
      <div :class="`${prefixCls}__menu_body`" @drop.prevent="drop2playlistHandler" @dragover.prevent>
        <div v-for="(v, i) in allFileList" :key="i" @click="viewItem(i)"
          :class="[`${prefixCls}__menu_item`, {active: i === statusCtrl.fileActiveIndex}]"
        >
          <div :class="`${prefixCls}__menu_item_label`" :title="v.label || `文件 ${i + 1}`">
            {{v.label || `文件 ${i + 1}`}}
          </div>
          <div :class="`${prefixCls}__menu_item_poster`" v-if="statusCtrl.showMenuPoster">
            <img :src="v.poster || undefined" @error="onImgError" />
          </div>
        </div>
        <p v-if="allFileList.length===0" :class="`${prefixCls}__menu_body-nodata`">暂无数据</p>
      </div>
      <div :class="`${prefixCls}__menu_btn`" @click="menuBtnClick">
        <i :class="[
          'xvu-iconfont',
          statusCtrl.collapsePlaylist ? 'xvu-collapse-right' : 'xvu-collapse-left'
        ]"></i>
      </div>
    </div>
  </div>
</template>

<script>
import ImageViewer from '@/components/image-viewer/index.js'
import Video from '@/components/video/index.js'
import Audio from '@/components/audio/index.js'
import Toast from '@/components/toast/index.js'
import PdfViewer from './pdf-viewer.vue'
import PdfViewerMobile from './pdf-viewer-mobile.vue'
import OfficeViewer from './office-viewer.vue'
import TextViewer from './text-viewer.vue'
import {deepCopy} from '@/script/utils.js'
const prefixCls = 'x-file-viewer'
export default {
  name: 'x-file-viewer',
  components: {
    ImageViewer,
    Video,
    Audio,
    PdfViewer,
    PdfViewerMobile,
    OfficeViewer,
    TextViewer,
  },
  props: {
    size: {
      type: String,
      default: 'default' // default|large|small
    },
    options: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  data() {
    return {
      prefixCls: prefixCls,
      statusCtrl: {
        collapsePlaylist: true,       // 折叠播放列表
        fileActiveIndex: -1,          // 当前文件序号
        currentSrc: '',               // 当前文件地址
        showMenu: 'auto',             // 是否显示文件列表
        showMenuPoster: false,        // 是否显示文件列表poster
        showMenuDelete: false,        // 是否显示文件列表清空按钮
      },
      fileList: [
        // 文件列表
        // {
        //   label: 'name',        // 文件名称
        //   url: '',              // 文件地址
        //   poster: '',           // 文件封面
        // }
      ],
      localFileList: []
    }
  },
  computed: {
    allFileList () {
      return [...this.fileList, ...this.localFileList]
    },
    localFileSign () {
      let result = []
      this.localFileList.forEach(v => {
        result.push([v.label, v.size, v.type, v.lastModified].join(';'))
      })
      return result
    },
    fileActive () {
      let result = this.allFileList[this.statusCtrl.fileActiveIndex] || {}
      return result
    },
    fileActiveComponent () {
      let result = ''
      if (/.(mp4|webm|ogg)$/i.test(this.fileActive.label)) result = 'Video'
      else if (/.(mp3|wav)$/i.test(this.fileActive.label)) result = 'Audio'
      else if (/.(gif|jpg|jpeg|png)$/i.test(this.fileActive.label)) result = 'ImageViewer'
      else if (/.(doc|docx|ppt|pptx|xls|xlsx)$/i.test(this.fileActive.label)) result = 'OfficeViewer'
      else if (/.(pdf)$/i.test(this.fileActive.label) && (this.options.platform === 'mobile')) result = 'PdfViewerMobile'
      else if (/.(pdf)$/i.test(this.fileActive.label)) result = 'PdfViewer'
      else result = 'TextViewer'
      return result
    },
    componentOptions () {
      let result = {}
      if (this.fileActiveComponent === 'Video') {
        result = {
          volume: 1, preload: 'auto', autoplay: true,
          showMenuDelete: true, autoHideToolsbar: false, fullscreenable: false,
          videoList: [ this.fileActive ]
        }
      } else if (this.fileActiveComponent === 'Audio') {
        result = {
          volume: 1, preload: 'auto', autoplay: true,
          showPanel: false, showMenuDelete: true, showVisualization: true, fftSize: 256,
          audioList: [ this.fileActive ]
        }
      } else if (this.fileActiveComponent === 'ImageViewer') {
        result = { width: '100%', height: '100%', imageUrl: this.fileActive.url, contain: true }
      } else if (this.fileActiveComponent === 'OfficeViewer') {
        result = { ...this.fileActive }
      } else if (this.fileActiveComponent === 'PdfViewerMobile') {
        result = { ...this.fileActive, pdfOpenParams: this.options.pdfOpenParams, platform: 'mobile' }
      } else if (this.fileActiveComponent === 'PdfViewer') {
        result = { ...this.fileActive, pdfOpenParams: this.options.pdfOpenParams }
      } else if (this.fileActiveComponent === 'TextViewer') {
        result = { ...this.fileActive, decode: this.options.txtDecode }
      }
      return result
    },
    showMenu () {
      let result = this.statusCtrl.showMenu
      if (this.statusCtrl.showMenu === 'auto') {
        result = (this.allFileList.length > 1)
      }
      return result
    }
  },
  watch: {
    options: {
      handler (n, o) {
        console.log(n, o)
        this.mergeOptions(n)
      },
      deep: true,
      immediate: true
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.init()
    })
  },
  methods: {
    init () {
      // 自动查看
      if (this.allFileList.length === 0) return
      this.viewItem(0)
    },
    mergeOptions (data) {
      Object.keys(data).forEach(k => {
        switch (k) {
          case 'showMenu':
          case 'showMenuPoster':
          case 'showMenuDelete':
            this.$set(this.statusCtrl, k, data[k])
            break
          case 'fileList':
            this[k] = deepCopy(data[k] || [])
            break
          case 'url':
            this.$set(this.statusCtrl, 'currentSrc', data[k] || '')
            break
        }
      })
    },
    // 图片错误处理
    onImgError (e) {
      let target = e.target || e.srcElement
      target.classList.add('error')
    },
    // 拖拽添加文件列表
    drop2playlistHandler (e) {
      let files = e.dataTransfer.files
      if (!files) return
      let localFileList = [...this.localFileList]
      for (let i = 0; i < files.length; i++) {
        let file = files[i]
        // 文件类型不存在即认为是文件夹或特殊文件
        // docx文件file.type为空
        if (/.(mp4|webm|ogg|mp3|wav|doc|docx|ppt|pptx|xls|xlsx|pdf|gif|jpg|jpeg|png|txt|jsp|php|html|js|css|ini|xml|json)$/i.test(file.name)) {
          window.URL = window.URL || window.webkitURL
          let url = window.URL.createObjectURL(file)
          // 去重
          let sign = [file.name, file.size, file.type, file.lastModified].join(';')
          if (!this.localFileSign.includes(sign)) {
            localFileList.push({
              label: file.name,
              url,
              size: file.size,
              type: file.type,
              lastModified: file.lastModified
            })
          }
        }
      }
      // 排序
      localFileList.sort((a, b) => {
        if (a.label > b.label) return 1
        else if (a.label === b.label) return 0
        else if (a.label < b.label) return -1
      })
      this.localFileList = localFileList
    },
    // 展开/收起播放列表
    menuBtnClick () {
      this.$set(this.statusCtrl, 'collapsePlaylist', !this.statusCtrl.collapsePlaylist)
    },
    // 清空播放列表
    menuDeleteClick () {
      this.$set(this.statusCtrl, 'fileActiveIndex', -1)
      this.$set(this.statusCtrl, 'currentSrc', '')
      this.localFileList = []
      this.fileList = []
    },
    // 查看指定文件
    viewItem (index) {
      let vItem = this.allFileList[index]
      if (!vItem || (this.statusCtrl.fileActiveIndex === index)) return
      this.$set(this.statusCtrl, 'fileActiveIndex', index)
      this.$set(this.statusCtrl, 'currentSrc', vItem.url || '')
      if (!this.fileActiveComponent) {
        Toast('不支持的文件格式')
      }
    },
  }
}
</script>
